package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"strings"

	"golang.org/x/tools/go/packages"
)

var supportTypes = map[string]struct{}{
	"int":        {},
	"int8":       {},
	"int16":      {},
	"int32":      {},
	"int64":      {},
	"uint":       {},
	"uint8":      {},
	"uint16":     {},
	"uint32":     {},
	"uint64":     {},
	"uintptr":    {},
	"float32":    {},
	"float64":    {},
	"complex64":  {},
	"complex128": {},
	"bool":       {},
	"string":     {},
	"byte":       {},
	"rune":       {},
	"error":      {},
	"any":        {},
}

// 判断是否基础类型
func isBuiltin(typeName string) bool {
	_, ok := supportTypes[typeName]
	return ok
}

// GoType -> TS Type 映射
var goToTsType = map[string]string{
	"int": "number", "int8": "number", "int16": "number", "int32": "number", "int64": "number",
	"uint": "number", "uint8": "number", "uint16": "number", "uint32": "number", "uint64": "number",
	"uintptr": "number",
	"float32": "number", "float64": "number",
	"complex64": "number", "complex128": "number",
	"string": "string",
	"bool":   "boolean",
	"byte":   "number",
	"rune":   "number",
	"any":    "any",
	"error":  "Error",
}

// FieldsToTSInterface 将解析后的 Go 函数参数转换成 TS interface
// name: interface 名称
func FieldsToTSInterface1(name string, fields []Field) string {
	var sb strings.Builder

	sb.WriteString(fmt.Sprintf("interface %s {\n", name))
	for _, f := range fields {
		tsType := GoTypeToTsType(f)
		sb.WriteString(fmt.Sprintf("  %s: %s;\n", f.Name, tsType))
	}
	sb.WriteString("}\n")

	return sb.String()
}

// GoTypeToTsType 根据 Field 类型生成 TS 类型
func GoTypeToTsType(f Field) string {
	// 内置类型直接映射
	if f.IsBuiltin {
		if t, ok := goToTsType[f.Type]; ok {
			return t
		}
		return "any"
	}

	// 自定义类型
	parts := strings.Split(f.Type, ".")
	typeName := parts[len(parts)-1]

	// 可以根据 Package 决定 import，这里仅返回类型名
	return typeName
}

func resolveImport(importPath string) ([]string, error) {
	importPath = strings.Trim(importPath, `"`)
	cfg := &packages.Config{
		Mode: packages.NeedFiles,
	}
	pkgs, err := packages.Load(cfg, importPath)
	if err != nil {
		return nil, err
	}
	if len(pkgs) == 0 {
		return nil, fmt.Errorf("no package found for %s", importPath)
	}
	return pkgs[0].GoFiles, nil // 返回某个源文件路径
}

func resolveStruct(importPath string, structName string) (*ast.StructType, map[string]string, error) {
	gofiles, err := resolveImport(importPath)
	if err != nil {
		return nil, nil, err
	}

	importMap := make(map[string]string)

	var ret *ast.StructType
	fset := token.NewFileSet()
	for _, file := range gofiles {
		if ret != nil {
			break
		}
		root, err := parser.ParseFile(fset, file, nil, parser.ParseComments)
		if err != nil {
			return nil, nil, err
		}

		for _, imp := range root.Imports {
			path := strings.Trim(imp.Path.Value, `"`)
			name := ""
			if imp.Name != nil {
				name = imp.Name.Name
			} else {
				parts := strings.Split(path, "/")
				name = parts[len(parts)-1]
			}
			importMap[name] = imp.Path.Value
		}

		ast.Inspect(root, func(node ast.Node) bool {
			switch x := node.(type) {
			case *ast.TypeSpec:
				if x.Name.Name == structName {
					ret = x.Type.(*ast.StructType)
					return false
				}
			}
			return true
		})
	}

	return ret, importMap, nil
}
